﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Common;

namespace GameClient
{
	public static class Client
	{
		#region Properties

		private static volatile TcpClient _tcpclient = null;
		private static string ServerName { get; set; }
		private static int ServerPort { get; set; }
		private static string UserName { get; set; }

		#endregion

		#region Events

		// Delegates
		public delegate void GameReceiveHandler(object sender, ClientEventArgs e);

		// Events
		// Server response
		public static event GameReceiveHandler LoginAnswer;
		public static event GameReceiveHandler LogoutAnswer;
		public static event GameReceiveHandler OpenGameAnswer;
		public static event GameReceiveHandler GameRequestAnswer;
		public static event GameReceiveHandler GameAcceptAnswer;
		public static event GameReceiveHandler ReadyAnswer;
		public static event GameReceiveHandler HitAnswer;
		public static event GameReceiveHandler SendMessageAnswer;
		public static event GameReceiveHandler ResignAnswer;
		public static event GameReceiveHandler UsersListAnswer;
        
		// Server initiated
		public static event GameReceiveHandler RequestReceived;
		public static event GameReceiveHandler MessageReceived;
		public static event GameReceiveHandler ResignReceived;
		public static event GameReceiveHandler MoveReceived;
        public static event GameReceiveHandler UsersListReceived;

		#endregion

		#region Private Methods

		static Client()
		{
			UserName = "";
			GetServerData();
		}

		private static void Listen()
		{
			while (true)
			{
				if (_tcpclient != null && _tcpclient.Connected && _tcpclient.GetStream().DataAvailable)
				{
					ServerCommand serverCmd = General.GetCommandFromStream(_tcpclient.GetStream()) as ServerCommand;
					if (serverCmd != null)
						ProcessServerMessage(serverCmd);
				}
				Thread.Sleep(100);
			}
		}

		private static void ProcessServerMessage(ServerCommand serverCmd)
		{
			if (serverCmd != null)
				switch (serverCmd.ComTypeClient)
				{
					case ClientCommandType.Null: // Command initiated by server
						switch (serverCmd.ComTypeServer)
						{
							case ServerCommandType.MoveResult:
								RaiseMoveReceivedEvent(serverCmd.Column, serverCmd.Row);
								break;
							case ServerCommandType.Message:
								RaiseMessageReceivedEvent(serverCmd.Message);
								break;
                            case ServerCommandType.OpenGames:
                                RaiseUsersListReceivedEvent(serverCmd.Message);
                                break;
						}
						SendSuccessCommand();
						break;
					case ClientCommandType.Login:
						UserName = (serverCmd.Answer) ? serverCmd.User : "";
						RaiseLoginAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.Logout:
						UserName = "";
						RaiseLogoutAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.GameOpen:
						RaiseOpenGameAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.GameRequest:
						RaiseGameRequestAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.GameAccept:
						RaiseGameAcceptAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.GameReady:
						RaiseReadyAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.GameMove:
						RaiseHitAnswerEvent(serverCmd.Message);
						break;
					case ClientCommandType.GameMoveResuslt:
						
						break;
					case ClientCommandType.GameNew:

						break;
					case ClientCommandType.GameResign:
						RaiseResignAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.Message:
						RaiseSendMessageAnswerEvent(serverCmd.Answer);
						break;
					case ClientCommandType.OpenGames:
						RaiseUsersListAnswerEvent(serverCmd.Message);
						break;
				}
		}

		private static void SendSuccessCommand()
		{
			ProcessClientMessage(new ClientCommand(UserName));
		}

		private static void GetServerData()
		{
			// Sould be web service for request server parameters
			ServerName = "localhost";
			ServerPort = 8010;
		}

		private static TcpClient GetTcpClient()
		{
			if (_tcpclient == null)
			{
				try
				{
					_tcpclient = new TcpClient("127.0.0.1", ServerPort);
					Thread th = new Thread(new ThreadStart(Listen));
					th.Start();
				}
				catch (SocketException)
				{ 
					// Can't connect to server
				}
			}
			return _tcpclient;
		}

		private static void ProcessClientMessage(ClientCommand cmd)
		{
			TcpClient client = GetTcpClient();
			StringBuilder str = new StringBuilder();
			byte[] msg = General.BuildRequest(cmd);
			if (client != null && client.Connected)
			{
				try
				{
					NetworkStream ns = client.GetStream();
					ns.Write(msg, 0, msg.Length); // Send move coordinates
				}
				catch
				{ 
					// Client was disconnected
				}
			}
		}

		private static void ClientClose()
		{
			if (_tcpclient != null)
				if (_tcpclient.Connected)
					_tcpclient.GetStream().Close();
			_tcpclient = null;
		}

		#region Raise Events

		private static void RaiseLoginAnswerEvent(bool val)
		{
			if (LoginAnswer != null)
				LoginAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseLogoutAnswerEvent(bool val)
		{
			if (LogoutAnswer != null)
				LogoutAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseOpenGameAnswerEvent(bool val)
		{
			if (OpenGameAnswer != null)
				OpenGameAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseGameRequestAnswerEvent(bool val)
		{
			if (GameRequestAnswer != null)
				GameRequestAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseGameAcceptAnswerEvent(bool val)
		{
			if (GameAcceptAnswer != null)
				GameAcceptAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseReadyAnswerEvent(bool val)
		{
			if (ReadyAnswer != null)
				ReadyAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseHitAnswerEvent(string msg)
		{
			if (HitAnswer != null)
				HitAnswer(null, new ClientEventArgs(msg));
		}
		private static void RaiseSendMessageAnswerEvent(bool val)
		{
			if (SendMessageAnswer != null)
				SendMessageAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseResignAnswerEvent(bool val)
		{
			if (ResignAnswer != null)
				ResignAnswer(null, new ClientEventArgs(val));
		}
		private static void RaiseUsersListAnswerEvent(string msg)
		{
			if (UsersListAnswer != null)
				UsersListAnswer(null, new ClientEventArgs(msg));
		}

		private static void RaiseMessageReceivedEvent(string msg)
		{
			if (MessageReceived != null)
				MessageReceived(null, new ClientEventArgs(msg));
		}
		private static void RaiseRequestReceivedEvent(string msg)
		{
			if (RequestReceived != null)
				RequestReceived(null, new ClientEventArgs(msg));
		}
		private static void RaiseResignReceivedEvent()
		{
			if (ResignReceived != null)
				ResignReceived(null, new ClientEventArgs(""));
		}
		private static void RaiseMoveReceivedEvent(int col,int row)
		{
			if (MoveReceived != null)
				MoveReceived(null, new ClientEventArgs(col, row));
		}

        private static void RaiseUsersListReceivedEvent(string msg)
        {
            if (UsersListReceived != null)
                UsersListReceived(null, new ClientEventArgs(msg));
        }

		#endregion

		#endregion

		#region Public Methods

		public static void Login(string user, string pwd)
		{
			ProcessClientMessage(new ClientCommand(user, pwd));
		}

		public static void Logout()
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.Logout, UserName, ""));
			Thread.Sleep(100);
			ClientClose();
		}

		public static void OpenNewGame()
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameOpen, UserName, ""));
		}

		public static void GameRequest(string user)
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameRequest, UserName, user));
		}

		public static void GameAccept(string user, bool accept)
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameAccept, UserName, user, accept));
		}

		public static void Ready()
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameReady, UserName, ""));
		}

		public static void GetHit(int col, int row)
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameMove, UserName, col, row, ""));
		}

		public static void HitResult(int col, int row, string msg)
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameMoveResuslt, UserName, col, row, msg));
		}

		public static void SendMessage(string message)
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.Message, UserName, message));
		}

		public static void Resign()
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.GameResign, UserName, ""));
		}

		public static void GetUsersList()
		{
			ProcessClientMessage(new ClientCommand(ClientCommandType.OpenGames, UserName, ""));
		}

		#endregion
	}
}